//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#include <bsp.h>
#include <mmu.h>
#include <init.h>
#include <bootinfo.h>
#include <timer.h>

#define __ELASTOS_MMU_H__
#include <ddk.h>

#include <nu_api.h>
#include <zenr_api.h>

#include <ktime.h>

STATIC DECL_CODEINIT void ParseBootCommandLine()
{
}

EXTERN_C DECL_CODEINIT void CDECL WriteFlash(BootInfo *pBootInfo);
EXTERN_C void InitBSPUser();

void **g_NucleusApiForZener;
ZENER_API *g_ZenerApiPtr;
Uint32 zenr_PSendAndWaitHandle(void *D, int Handle);
Uint32 zenr_PSendHandle(void *D, int Handle);

extern timezone tz;

DECL_ASMLINKAGE DECL_CODEINIT void BspStartup(BootInfo *pBootInfo)
{
    g_NucleusApiForZener = (void**)pBootInfo->Reserved1;
    g_ZenerApiPtr = (ZENER_API*)pBootInfo->Reserved2;

    void (DzEvent::*temp)(EventState state) = &DzEvent::NotifyByIsr;

    zapi_System->init_ZAPI(
                    &zenr_PSendAndWaitHandle,
                    &zenr_PSendHandle,
                    *(void (**)(Uint32, Uint32))&temp,
                    (void *)&tz);

    if (ZENR_ASYNC_API_MAX_INDEX != pBootInfo->Reserved3
        || NUMBER_OF_ZAPI != g_ZenerApiPtr->ulNumOfZAPI) {
        nu_puts("!!!!!!!!!!!!!! ERROR: Hogwarts.raw NOT match Elastos.raw !!!!!!!!!!!!!!\n"
                "!!!!!!!!!!!!!!     Please do a clean build! System Halt! !!!!!!!!!!!!!!\n");

        for (UInt32 offset = 0; offset < 400 * 240; offset++) {
            *((UInt32*)0x11000000 + offset) = 0x000000FF;
        }
        nu_displayLoad((Uint8*)0x11000000,
                        0, 0, 240, 400, 240,
                        0, 0, 0);
        while (1);
    }

    nu_puts("Init g_NucleusApiForZener OK!\n");

    kprintf("\n<Boot Info> (0x%08x)\n"
            "LoadAddress:       0x%08x\n"
            "ImageBase:         0x%08x\n"
            "ImageSize:         0x%08x\n"
            "MemorySize:        0x%08x\n"
            "WriteMagic:        0x%08x\n",
            pBootInfo,
            pBootInfo->LoadAddress,
            pBootInfo->ImageBase,
            pBootInfo->ImageSize,
            pBootInfo->MemorySize,
            pBootInfo->WriteMagic);

#if 0

    nuMmu_SectInfo *pSectInfo;
    nuMmu_SmallPageInfo *pSmallPageInfo;
    Uint8 sectInfoSize, smallPageSize;

    nu_getMmuSectInfo(&pSectInfo, &sectInfoSize);
    nu_getMmuSmallPageInfo(&pSmallPageInfo, &smallPageSize);

    int i;
    nu_puts("====================== SectInfo ======================\n");
    for (i = 0; i < sectInfoSize; i++) {
        kprintf("index %2d: pa:0x%08x va:0x%08x num:%3d access:%d c&b:%d domain:%d\n",
                    i,
                    pSectInfo[i].pa,
                    pSectInfo[i].va,
                    pSectInfo[i].numEntries,
                    pSectInfo[i].access,
                    pSectInfo[i].cacheAndBufferAble,
                    pSectInfo[i].domain);
    }
    nu_puts("======================================================\n\n");

    nu_puts("==================== SmallPageInfo ====================\n");
    for (i = 0; i < smallPageSize; i++) {
        kprintf("index %2d: pa:0x%08x va:0x%08x cof:%d num:%3d ap0:%d ap1:%d ap2:%d ap3:%d c&b:%d domain:%d\n",
                    i,
                    pSmallPageInfo[i].pa,
                    pSmallPageInfo[i].va,
                    pSmallPageInfo[i].coarseOrFineTtb,
                    pSmallPageInfo[i].numEntries,
                    pSmallPageInfo[i].ap0,
                    pSmallPageInfo[i].ap1,
                    pSmallPageInfo[i].ap2,
                    pSmallPageInfo[i].ap3,
                    pSmallPageInfo[i].cacheAndBufferAble,
                    pSmallPageInfo[i].domain);
    }
    nu_puts("======================================================\n\n");

#endif

    // Setup
    KrnSetup(
        KERNEL_PHYSBASE, KERNEL_IMAGEPHYSBASE,
        KERNEL_MEMMAPPEDIOBASE, KERNEL_MEMMAPPEDIOLIMIT,
        0, 0);

//    pBootInfo = (BootInfo *)VIRTADDR((physaddr_t)pBootInfo);
//
//    kprintf("\n<Boot Info> (0x%08x)\n"
//            "LoadAddress:       0x%08x\n"
//            "ImageBase:         0x%08x\n"
//            "ImageSize:         0x%08x\n"
//            "MemorySize:        0x%08x\n"
//            "WriteMagic:        0x%08x\n",
//            pBootInfo,
//            pBootInfo->LoadAddress,
//            pBootInfo->ImageBase,
//            pBootInfo->ImageSize,
//            pBootInfo->MemorySize,
//            pBootInfo->WriteMagic);

    // Initialize
    InitConsole();

    InitBootModules();

    ParseBootCommandLine();

    InitMemoryZones();

    InitRTC();

    InitPIC();

    InitPIT();

#if !defined(_TEST_TYPE) /* Test console uses serial3 */
//    InitBSPUser();
#endif //_TEST_TYPE

    if (!KrnInitialize()) {
        BspHalt();
    }

    KrnStartup();

    assert0msg("Kernel startup failed");
    BspHalt();
}

BspGlobals bsp = {
    "ARM",                    // *szCpuDescription
    "sharp",                  // *szBoardDescription

    KERNEL_PHYSBASE,          // paKernelPhysBase
    KERNEL_IMAGEPHYSBASE,     // paKernelImagePhysBase

    NULL,                     // *pMemoryZones
    0,                        // uNumberOfMemoryZones

    NULL,                     // *pMemoryHoles
    0,                        // uNumberOfMemoryHoles

    0,                        // uDmaPreferredZoneNo
    0,                        // uKernelPreferredZoneNo
    0,                        // uUserPreferredZoneNo

    {0, 0},                   // regionOfInitStack

    NULL,                     // *pBootModules
    0,                        // uNumberOfBootModules
    {0, 0},                   // regionOfBootModules

    NULL,                     // *szBootCommandLine

    0,                        // uIrqBase
    39,                       // uNumberOfIrqs

    PIT_Irq,                  // irqOfPIT
    IPL0                      // iplOfPIT
};

//EXTERN_C void CDECL BspBeep()
//{
//    assert(0);
//}
//
//EXTERN_C irqs_t CDECL BspGetIrqs()
//{
//    assert(0);
//    return 0;
//}
//
//EXTERN_C void CDECL BspMaskIrqs(irqs_t irqs, bool_t bEnable)
//{
//    assert(0);
//}
//
//EXTERN_C void CDECL BspMaskAllIrqs(bool_t bEnable)
//{
//    assert(0);
//}
//
//EXTERN_C void CDECL BspAcknowledgeIrq(irq_t irq)
//{
//    assert(0);
//}
//
//EXTERN_C void   CDECL BspReloadPIT()
//{
//    assert(0);
//}
//
//EXTERN_C uint_t CDECL BspGetPITTime()
//{
//    assert(0);
//    return 0;
//}
//
//EXTERN_C void   CDECL BspGetRTCTime(RTCTime *pRTCTime)
//{
//    assert(0);
//}
//
//EXTERN_C void   CDECL BspSetRTCTime(const RTCTime *pRTCTime)
//{
//    assert(0);
//}

